package com.longma.server.util;

import java.util.Arrays;

/**
 * 数学通用类
 */
public class MathUtil {
    /**
     * 如果数据不存在 转为0
     * @return
     */
    public static Integer computeIfAbsent(Integer number){
        if(number == null){
            return 0;
        }
        return number;
    }

    public static Double computeIfAbsent(Double number){
        if(number == null){
            return 0.0;
        }
        return number;
    }

    /**
     * 保留两位小数
     */
    public static double round(double value){
        return  Math.round(value*100)/100.0;
    }



    /**
     * 计算1,2,3,...,x.length-1阶均差
     *  x             x0            x1          x2           x3                 ....
     *  y             y0            y1          y2           y3                 ....
     *  1阶均差                     t[x0,x1]     t[x1,x2]     t[x2,x3]           ....
     *  2阶均差                                  t[x0,x1,x2]  t[x1,x2,x3]         ....
     *  3阶均差                                               t[x0,x1,x2,x3]      ....
     *  ...                                                                       ....
     *  x.length-1阶均差
     * t[xi,xj] = (yi-yj)/(xi-xj)
     * t[xi,xj,xk] = (t[i,j] - t[j,k])/(xi-xk)
     * https://www.cnblogs.com/jake9402/p/7593694.html
     */
    public static double[][] getOrderDiffQuot(double[] x,double[] y){
        // 参数校验
        if(x == null || y == null){
            throw new IllegalArgumentException();
        }

        if(x.length != y.length){
            throw new IllegalArgumentException();
        }

         // 节点个数
        int n = x.length;
        double[][] t= new double[n][n];

        // 复制
        t[0] = Arrays.copyOfRange(y,0,n);

        // 计算差商
        for(int i=1;i<n;i++){
            for(int j=i;j<n;j++){
                t[i][j] = (t[i-1][j] - t[i-1][j-1])/(x[j] - x[j-1]);
            }
        }
        return t;
    }

    /**
     * 获取牛顿插值
     * @param t: 均差表   由getOrderDiffQuot计算得到
     * @param x：x轴坐标
     * @param num: 需要计算插值的x轴坐标
     * @param newtonTime: 牛顿迭代插值多项式次数  0：默认最大迭代次数
     * N(x) = t(x0) + t[x0,x1](x-x0) + f[x0,x1,x2](x-x0)(x-x1) + ... + f[x0,x1,...,xn](x-x0)(x-x1)...(x-x(n-1))
     * https://www.zhihu.com/question/22320408/answer/141973314
     */
    public static double getNewtonInterpolate(double[][] t,double[] x,double num,int newtonTime){
       double result = 0.0;

       // 最大迭代次数
        if(newtonTime <=0 ){
            newtonTime = x.length-1;
        }else {
            newtonTime = Math.min(newtonTime, x.length - 1);
        }
       for(int i=0;i<newtonTime;i++){
           double temp = t[i][i];
           for(int j=0;j<i;j++){
               temp *= num - x[j];
           }
           result += temp;
       }
        return result;
    }

    public static void main(String[] args){
        double[] x = {0.4,0.55,0.65,0.8,0.9,1.05};
        double[] y = {0.41075,0.57815,0.69675,0.88811,1.02652,1.25382};
        double[][] t =  getOrderDiffQuot(x,y);
        getNewtonInterpolate(t,x,0.596,5);
    }
}
